﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Ivy.Common.Framework.GeneralUtility
{
    public static class StringUtility
    {
        #region Variables & Constants
        // This constant string is used as a "salt" value for the PasswordDeriveBytes function calls. 
        // This size of the IV (in bytes) must = (keysize / 8).  Default keysize is 256, so the IV must be 
        // 32 bytes long.  Using a 16 character string here gives us 32 bytes when converted to a byte array. 
        private const string initCryptoVector = "tu89geji340t89u2";

        // This constant is used to determine the keysize of the encryption algorithm. 
        private const int CryptoKeySize = 256;

        // This constant is used to provide the default PassKey in client app is not supplying.
        private const string CryptoDefaultPassKey = "Ivy";

        #endregion Variables & Constants

        #region Constructor & Destructor
        #endregion Constructor & Destructor

        #region Public Properties
        #endregion Public Properties

        #region Public Methods
        public static string GenerateRandomString(int outPutStringLength)
        {
            string _outPutString = string.Empty;
            int _seedValue = (int)DateTime.Now.Ticks;
            _outPutString = GenerateRandomString(outPutStringLength, _seedValue);
            return _outPutString;
        }
        public static string GenerateRandomString(int outPutStringLength, int seedKey)
        {
            string _outPutString = string.Empty;
            StringBuilder _Strbuilder = new StringBuilder();
            Random _Randomizer = new Random(seedKey);
            char _AsciiChar;
            for (int _loopCounetr = 0; _loopCounetr < outPutStringLength; _loopCounetr++)
            {
                _AsciiChar = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * _Randomizer.NextDouble() + 65)));
                _Strbuilder.Append(_AsciiChar);
            }
            _outPutString = _Strbuilder.ToString();
            return _outPutString;
        }

        public static int GenerateRandomNumber(int minRange, int maxRange)
        {
            int _outPutNumber = 0;
            int _seedValue = (int)DateTime.Now.Ticks;
            _outPutNumber = GenerateRandomNumber(minRange, maxRange, _seedValue);
            return _outPutNumber;
        }
        public static int GenerateRandomNumber(int minRange, int maxRange, int seedKey)
        {
            int _outPutNumber = 0;
            Random _Randomizer = new Random(seedKey);
            _outPutNumber = _Randomizer.Next(minRange, maxRange);
            return _outPutNumber;
        }
        public static int GenerateRandomNumber()
        {
            int _outPutNumber = 0;
            int _seedValue = (int)DateTime.Now.Ticks;
            _outPutNumber = GenerateRandomNumber(_seedValue);
            return _outPutNumber;
        }
        public static int GenerateRandomNumber(int seedKey)
        {
            int _outPutNumber = 0;
            Random _Randomizer = new Random(seedKey);
            _outPutNumber = _Randomizer.Next();
            return _outPutNumber;
        }

        public static string EncryptString(string inPutPlainString)
        {
            string _outPutString = string.Empty;
            string _PassKeyValue = CryptoDefaultPassKey;
            _outPutString = EncryptString(inPutPlainString, _PassKeyValue);
            return _outPutString;
        }
        public static string EncryptString(string inPutPlainString, string passKey)
        {
            string _outPutString = string.Empty;
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initCryptoVector);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(inPutPlainString);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passKey, null);
            byte[] keyBytes = password.GetBytes(CryptoKeySize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            byte[] cipherTextBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();
            _outPutString = Convert.ToBase64String(cipherTextBytes);
            return _outPutString;
        }

        public static string DecryptString(string inPutEncryptedString)
        {
            string _outPutString = string.Empty;
            string _PassKeyValue = CryptoDefaultPassKey;
            _outPutString = DecryptString(inPutEncryptedString, _PassKeyValue);
            return _outPutString;
        }
        public static string DecryptString(string inPutEncryptedString, string passKey)
        {
            string _outPutString = string.Empty;
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initCryptoVector);
            byte[] cipherTextBytes = Convert.FromBase64String(inPutEncryptedString);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passKey, null);
            byte[] keyBytes = password.GetBytes(CryptoKeySize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            _outPutString = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
            return _outPutString;
        }

        /// <summary>
        /// For stripping out HTML tags while preserving most basic formatting. In other words, it converts HTML to plain text.
        /// http://www.codeproject.com/Articles/11902/Convert-HTML-to-Plain-Text
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ConvertHtmlToString(string source)
        {
            try
            {
                string result;

                // Remove HTML Development formatting
                // Replace line breaks with space
                // because browsers inserts space
                result = source.Replace("\r", " ");
                // Replace line breaks with space
                // because browsers inserts space
                result = result.Replace("\n", " ");
                // Remove step-formatting
                result = result.Replace("\t", string.Empty);
                // Remove repeating spaces because browsers ignore them
                result = System.Text.RegularExpressions.Regex.Replace(result, @"( )+", " ");

                // Remove the header (prepare first by clearing attributes)
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*head([^>])*>", "<head>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"(<( )*(/)( )*head( )*>)", "</head>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(<head>).*(</head>)", string.Empty,
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // remove all scripts (prepare first by clearing attributes)
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*script([^>])*>", "<script>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"(<( )*(/)( )*script( )*>)", "</script>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                //result = System.Text.RegularExpressions.Regex.Replace(result,
                //         @"(<script>)([^(<script>\.</script>)])*(</script>)",
                //         string.Empty,
                //         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"(<script>).*(</script>)", string.Empty,
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // remove all styles (prepare first by clearing attributes)
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*style([^>])*>", "<style>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"(<( )*(/)( )*style( )*>)", "</style>",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(<style>).*(</style>)", string.Empty,
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // insert tabs in spaces of <td> tags
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*td([^>])*>", "\t",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // insert line breaks in places of <BR> and <LI> tags
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*br( )*>", "\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*li( )*>", "\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // insert line paragraphs (double line breaks) in place
                // if <P>, <DIV> and <TR> tags
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*div([^>])*>", "\r\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*tr([^>])*>", "\r\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<( )*p([^>])*>", "\r\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // Remove remaining tags like <a>, links, images,
                // comments etc - anything that's enclosed inside < >
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"<[^>]*>", string.Empty,
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // replace special characters:
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @" ", " ",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&bull;", " * ",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&lsaquo;", "<",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&rsaquo;", ">",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&trade;", "(tm)",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&frasl;", "/",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&lt;", "<",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&gt;", ">",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&copy;", "(c)",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&reg;", "(r)",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                // Remove all others. More can be added, see
                // http://hotwired.lycos.com/webmonkey/reference/special_characters/
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         @"&(.{2,6});", string.Empty,
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // for testing
                //System.Text.RegularExpressions.Regex.Replace(result,
                //       this.txtRegex.Text,string.Empty,
                //       System.Text.RegularExpressions.RegexOptions.IgnoreCase);

                // make line breaking consistent
                result = result.Replace("\n", "\r");

                // Remove extra line breaks and tabs:
                // replace over 2 breaks with 2 and over 4 tabs with 4.
                // Prepare first to remove any whitespaces in between
                // the escaped characters and remove redundant tabs in between line breaks
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\r)( )+(\r)", "\r\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\t)( )+(\t)", "\t\t",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\t)( )+(\r)", "\t\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\r)( )+(\t)", "\r\t",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                // Remove redundant tabs
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\r)(\t)+(\r)", "\r\r",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                // Remove multiple tabs following a line break with just one tab
                result = System.Text.RegularExpressions.Regex.Replace(result,
                         "(\r)(\t)+", "\r\t",
                         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                // Initial replacement target string for line breaks
                string breaks = "\r\r\r";
                // Initial replacement target string for tabs
                string tabs = "\t\t\t\t\t";
                for (int index = 0; index < result.Length; index++)
                {
                    result = result.Replace(breaks, "\r\r");
                    result = result.Replace(tabs, "\t\t\t\t");
                    breaks = breaks + "\r";
                    tabs = tabs + "\t";
                }

                // That's it.
                return result;
            }
            catch
            {
                //MessageBox.Show("Error");
                return source;
            }
        }
        #endregion Public Methods

        #region Events
        #endregion Events

        #region Private Methods
        #endregion Private Methods
    }
}
